﻿using System;
using System.Reflection;
using MugenInjection.Delegates;
using MugenInjection.Infrastructure;
using MugenInjection.Interface;
#if !NOEXPRESSION
using System.Linq.Expressions;
#endif

namespace MugenInjection.Syntax.Method
{
    /// <summary>
    /// Specific fluent syntax for method binding.
    /// </summary>
    public interface IMethodWithSyntax : IBindingBuilder
    {
        /// <summary>
        /// Indicates that the service should be use specified constructor argument.
        /// </summary>
        /// <param name="name">The specified parameter name.</param>
        /// <param name="value">The specified parameter value.</param>
        /// <returns>The fluent syntax.</returns>
        IMethodCallbackObjectUseWithSyntax WithConstructorArgument(string name, object value);


        /// <summary>
        /// Indicates that the service should be use specified constructor argument.
        /// </summary>
        /// <param name="name">The specified parameter name.</param>
        /// <param name="parameterDelegate">The specified <see cref="ParameterDelegate{T}"/>.</param>
        /// <returns>The fluent syntax.</returns>
        IMethodCallbackObjectUseWithSyntax WithConstructorArgument(string name, ParameterDelegate<object> parameterDelegate);

        /// <summary>
        /// Indicates that the service should be use specified method argument.
        /// </summary>
        /// <param name="methodName">The specified method name.</param>
        /// <param name="name">The specified parameter name.</param>
        /// <param name="value">The specified parameter value.</param>
        /// <returns>The fluent syntax.</returns>
        IMethodCallbackObjectUseWithSyntax WithMethodArgument(string methodName,  string name, object value);

        /// <summary>
        /// Indicates that the service should be use specified method argument.
        /// </summary>
        /// <param name="methodName"></param>
        /// <param name="name">The specified parameter name.</param>
        /// <param name="parameterDelegate">The specified <see cref="ParameterDelegate{T}"/>.</param>
        /// <returns>The fluent syntax.</returns>
        IMethodCallbackObjectUseWithSyntax WithMethodArgument(string methodName,  string name,
                                                                  ParameterDelegate<object> parameterDelegate);

        /// <summary>
        /// Indicates that the service should be use specified property argument.
        /// </summary>
        /// <param name="name">The specified property name.</param>
        /// <param name="value">The specified property value.</param>
        /// <returns>The fluent syntax.</returns>
        IMethodCallbackObjectUseWithSyntax WithPropertyValue(string name, object value);

        /// <summary>
        /// Indicates that the service should be use specified property argument.
        /// </summary>
        /// <param name="name">The specified property name.</param>
        /// <param name="parameterDelegate">The specified <see cref="ParameterDelegate{T}"/>.</param>
        /// <returns>The fluent syntax.</returns>
        IMethodCallbackObjectUseWithSyntax WithPropertyValue(string name,  ParameterDelegate<object> parameterDelegate);

        /// <summary>
        /// Indicates that the service should be use specified custom argument.
        /// </summary>
        /// <param name="parameter">The specified <see cref="IInjectionParameter"/>.</param>
        /// <returns>The fluent syntax.</returns>
        IMethodCallbackObjectUseWithSyntax WithParameter(IInjectionParameter parameter);
    }

    /// <summary>
    /// Specific fluent syntax for method binding.
    /// </summary>
    public interface IMethodWithSyntax<T> : IBindingBuilder
    {
#if NOEXPRESSION
        /// <summary>
        /// Indicates that the service should be use specified constructor argument.
        /// </summary>
        /// <param name="name">The specified parameter name.</param>
        /// <param name="value">The specified parameter value.</param>
        /// <returns>The fluent syntax.</returns>
        IMethodCallbackObjectUseWithSyntax<T> WithConstructorArgument(string name, object value);


        /// <summary>
        /// Indicates that the service should be use specified constructor argument.
        /// </summary>
        /// <param name="name">The specified parameter name.</param>
        /// <param name="parameterDelegate">The specified <see cref="ParameterDelegate{T}"/>.</param>
        /// <returns>The fluent syntax.</returns>
        IMethodCallbackObjectUseWithSyntax<T> WithConstructorArgument(string name, ParameterDelegate<object> parameterDelegate);

        /// <summary>
        /// Indicates that the service should be use specified method argument.
        /// </summary>
        /// <param name="methodName">The specified method name.</param>
        /// <param name="name">The specified parameter name.</param>
        /// <param name="value">The specified parameter value.</param>
        /// <returns>The fluent syntax.</returns>
        IMethodCallbackObjectUseWithSyntax<T> WithMethodArgument(string methodName, string name, object value);

        /// <summary>
        /// Indicates that the service should be use specified method argument.
        /// </summary>
        /// <param name="methodName"></param>
        /// <param name="name">The specified parameter name.</param>
        /// <param name="parameterDelegate">The specified <see cref="ParameterDelegate{T}"/>.</param>
        /// <returns>The fluent syntax.</returns>
        IMethodCallbackObjectUseWithSyntax<T> WithMethodArgument(string methodName, string name,
                                                                  ParameterDelegate<object> parameterDelegate);

        /// <summary>
        /// Indicates that the service should be use specified property argument.
        /// </summary>
        /// <param name="name">The specified property name.</param>
        /// <param name="value">The specified property value.</param>
        /// <returns>The fluent syntax.</returns>
        IMethodCallbackObjectUseWithSyntax<T> WithPropertyValue(string name, object value);

        /// <summary>
        /// Indicates that the service should be use specified property argument.
        /// </summary>
        /// <param name="name">The specified property name.</param>
        /// <param name="parameterDelegate">The specified <see cref="ParameterDelegate{T}"/>.</param>
        /// <returns>The fluent syntax.</returns>
        IMethodCallbackObjectUseWithSyntax<T> WithPropertyValue(string name, ParameterDelegate<object> parameterDelegate);

        /// <summary>
        /// Indicates that the service should be use specified custom argument.
        /// </summary>
        /// <param name="parameter">The specified <see cref="IInjectionParameter"/>.</param>
        /// <returns>The fluent syntax.</returns>
        IMethodCallbackObjectUseWithSyntax<T> WithParameter(IInjectionParameter parameter);
#else
        /// <summary>
        /// Indicates that the service should be use specified method arguments.
        /// </summary>
        /// <param name="constructorCall">The specified new instance expression.</param>
        /// <returns>The fluent syntax.</returns>
        IMethodCallbackObjectUseWithSyntax<T> WithConstructorArguments(Expression<Func<ResolveContext, T>> constructorCall);

        /// <summary>
        /// Indicates that the service should be use specified property argument.
        /// </summary>
        /// <param name="property">The property access expression.</param>
        /// <param name="value">The specified property value.</param>
        /// <returns>The fluent syntax.</returns>
        IMethodCallbackObjectUseWithSyntax<T> WithPropertyValue<TValue>(System.Linq.Expressions.Expression<Func<T, TValue>> property, TValue value);

        /// <summary>
        /// Indicates that the service should be use specified method arguments.
        /// </summary>
        /// <param name="methodCall">The specified method call expression.</param>
        /// <returns>The fluent syntax.</returns>
        IMethodCallbackObjectUseWithSyntax<T> WithMethodArguments(Expression<Action<ResolveContext, T>> methodCall);

        /// <summary>
        /// Indicates that the service should be use specified custom argument.
        /// </summary>
        /// <param name="parameter">The specified <see cref="IInjectionParameter"/>.</param>
        /// <returns>The fluent syntax.</returns>
        IMethodCallbackObjectUseWithSyntax<T> WithParameter(IInjectionParameter parameter);
#endif
    }
}